#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
using namespace std;
namespace lxp
{

    template <class T>
    class RingBuffer
    {

    public:
        RingBuffer(int cap)
            : _ring(cap),
              _cap(cap),
              _c_cap(0),
              _p_cap(0)
        {
            sem_init(&_datasem, 0, 1);
            sem_init(&_spacesem, 0, 1);
            pthread_mutex_init(&p_lock, nullptr);
            pthread_mutex_init(&c_lock, nullptr);
        }
        void Equeue(const T &in)
        {
            sem_wait(&_spacesem);
            pthread_mutex_lock(&p_lock);
            _ring[_p_cap] = in;
            _p_cap++;
            _p_cap %= _cap;
            pthread_mutex_unlock(&p_lock);
            sem_post(&_datasem);
        }
        void Pop(T *out)
        {
            sem_wait(&_datasem);
            pthread_mutex_lock(&c_lock);
            *out = _ring[_c_cap];
            _c_cap++;
            _c_cap %= _cap;
            pthread_mutex_unlock(&c_lock);
            sem_post(&_spacesem);
        }
        ~RingBuffer()
        {
            sem_destroy(&_datasem);
            sem_destroy(&_spacesem);
            pthread_mutex_destroy(&p_lock);
            pthread_mutex_destroy(&c_lock);
        }

    private:
        std::vector<T> _ring;
        int _cap;
        int _c_cap;
        int _p_cap;
        sem_t _datasem;
        sem_t _spacesem;

        pthread_mutex_t p_lock;
        pthread_mutex_t c_lock;
    };
}